
import face_recognition
from flask import Flask, jsonify, request, send_file , render_template , abort
from SqlHelper import SqlHelper
import ImgUtils
import re
from numpy import array , float64
import time
import json
from paddleocr import PaddleOCR
import cv2
import configparser
import os
from gevent import pywsgi

config = configparser.ConfigParser()
config.read("config.ini")
ALLOWED_EXTENSIONS = {'png', 'jpg', 'jpeg', 'gif'}
AMIND_LOCALTION = {"/tokens","/faces","/tokens/add","/tokens/del","/tokens/edit","/orc"}

app = Flask(__name__)
sql = SqlHelper()
imgUtils = ImgUtils.ImgUtils()

orc = PaddleOCR()

API_TOKEN = {
    "token":config.get("TOKEN","token"),
    "id":-1
}

def allowed_file(filename):
    return '.' in filename and \
           filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS

@app.route('/face/list', methods=['POST'])
def faces():
    strPage = request.json.get("page")
    isMatch = re.match("^\d{1,}$",str(strPage))
    if isMatch:
        page = int(strPage)
        _page = (page-1) * 20
        params = (_page,_page+20)
        # datas = sql.select_infor("SELECT ff.id as id,info,face_path,ff.`name` as faceName,note,ff.creat_at,ff.update_at,st.id as tokenID,st.`name` as tokenName FROM faceinfo as ff JOIN systoken as st on ff.token_id=st.id LIMIT %s,%s",params)
        datas = sql.select_infor("SELECT ff.id as faceId,info,face_path,ff.`name` as faceName,note,ff.creat_at,ff.update_at FROM faceinfo as ff  LIMIT %s,%s",params)
        return jsonify({
            "code":1,
            "data":datas,
            "msg":"success"
        })
    else:
        return jsonify({
            "code":0,
            "msg":"参数错误[page]"
        })

# 提交        
@app.route('/ocr', methods=['POST'])
def ocr():
    url = request.json.get("url",None)
    clip = request.json.get("clip",False)
    if url == None:
        return jsonify({
            "code":0,
            "msg":"参数错误[url]"
        })
    
    local_path = imgUtils.downImgae4url(url)
    if local_path == None:
        return jsonify({
            "code":0,
            "msg":"下载文件异常[url]"
        })

    img = cv2.imread(local_path)
    clipImg = None
    if clip:
        h = img.shape[0]
        w = img.shape[1]
        mh = int( 180 / 750 * h)
        top = int( h / 2 - mh/2)
        clipImg = img[top:top+mh,0:w]
    orcImg = clipImg if clip  else img
    list = orc.ocr(orcImg)
    if clip:
        dir = imgUtils.getAndCreatFolder("CLIP")
        clipPath = os.path.join(dir,imgUtils.getFileName4path(local_path))
        cv2.imwrite(clipPath,orcImg)

    return jsonify({
        "code":1,
        "data":{
            "ocr":list,
            "img":local_path
        }
    })


@app.route('/face/register', methods=['POST'])
def face_register():
    url = request.json.get("url",None)
    if url == None:
        return jsonify({
            "code":0,
            "msg":"参数错误[url]"
        })
    local_url = imgUtils.downImgae4url(url)
    if local_url == None:
         return jsonify({
            "code":0,
            "msg":"下载文件异常[url]"
        })

    img = face_recognition.load_image_file(local_url)
    face_encodings = face_recognition.face_encodings(img)
    if face_encodings != None and len(face_encodings) == 1:
        listFaceInfo = str(face_encodings[0].tolist())
        tokenInfo = request.mdata
        name = request.json.get("faceName","N/A")
        note = request.json.get("note","N/A")
        creat_at = time.strftime("%Y-%m-%d %H:%M:%S")
        params = (tokenInfo['id'],listFaceInfo,local_url,name,note,creat_at)
        sqlStr = 'INSERT  INTO faceinfo (token_id,info,face_path,`name`,note,creat_at) VALUE (%s,%s,%s,%s,%s,%s)'
        insertId = sql.insert_infor(sqlStr,params)
        if insertId != 0:
            return jsonify({
                "data":{
                    "faceId":insertId,
                    "img":local_url
                },
                "msg":"注册成功",
                "code":1
            })
        else:
            return jsonify({
                "msg":"注册失败",
                "code":-1
            })
    else:
        return jsonify({
            "face_encoding":"未识别到人脸" if len(face_encodings)==0 else "识别到多个人脸",
            "code":0
        })
    
@app.route('/face/compare', methods=['POST'])
def face_compare():
    faceId = request.json.get("faceId",None)
    url = request.json.get("url",None)
    tolerance = float(request.json.get("tolerance","0.6"))
    if faceId == None:
        return jsonify({
            "code":0,
            "msg":"参数错误[faceId]"
        })
    
    if url == None:
        return jsonify({
            "code":0,
            "msg":"参数错误[url]"
        })
    
    query = sql.select_infor("select id,info from faceinfo where id = %s",(faceId))
    if len(query) == 0:
        return jsonify({
            "code":0,
            "msg":"人脸未注册或已删除"
        })
    
    local_url = imgUtils.downImgae4url(url)
    if local_url==None:
        return jsonify({
            "code":0,
            "msg":"下载文件异常[url]"
        })
    
    img = face_recognition.load_image_file(local_url)
    face_encodings = face_recognition.face_encodings(img)
    if len(face_encodings) == 1:
        faceInfo = jsonStr2arr(query[0]['info'])
        comparedFace = face_recognition.compare_faces([faceInfo],face_encodings[0],tolerance=tolerance)
        if comparedFace[0]:
            return jsonify({
                "code":1,
                "data":{
                    "faceId":faceId,
                    "img":local_url
                },
                "msg":"人脸对比成功"
            })
        else:
             return jsonify({
                "code":0,
                "msg":"人脸对比失败"
            })
    else:
        return jsonify({
            "msg":"未识别到人脸" if len(face_encodings)==0 else "识别到多个人脸",
            "code":0
        })
    
@app.route('/face/delete', methods=['POST'])
def face_delete():
    faceId = request.json.get("faceId",None)
    if faceId == None:
        return jsonify({
            "code":0,
            "msg":"参数错误[faceId]"
        })
    
    affected_row = sql.update_infor("DELETE FROM faceinfo WHERE faceinfo.id=%s",(faceId))
    if affected_row == 0:
        return jsonify({
            "code":0,
            "msg":"人脸未注册或已删除"
        })
    else:
        return jsonify({
            "msg":"删除成功！",
            "code":1
        })

@app.route('/face/update', methods=['POST'])
def face_update():
    faceId = request.json.get("faceId",None)
    url = request.json.get("url",None)
    faceName = request.json.get("faceName",None)

    if faceId == None:
        return jsonify({
            "code":0,
            "msg":"参数错误[faceId]"
        })
    if url == None:
        return jsonify({
            "code":0,
            "msg":"参数错误[url]"
        })
    query = sql.select_infor("select id,name,info from faceinfo where id = %s",(faceId))
    if len(query) == 0:
        return jsonify({
            "code":0,
            "msg":"人脸未注册或已删除"
        })
    local_path = imgUtils.downImgae4url(url)
    if local_path == None:
         return jsonify({
            "code":0,
            "msg":"图片信息下载错误"
        })

    file = face_recognition.load_image_file(local_path)
    face_encodings = face_recognition.face_encodings(file)
    if face_encodings != None and len(face_encodings) == 1:
        listFaceInfo = str(face_encodings[0].tolist())
        name = faceName if faceName !=None else query[0]['name']
        affected_row = sql.update_infor("UPDATE faceinfo set info=%s,face_path=%s,name=%s  WHERE faceinfo.id=%s",(listFaceInfo,local_path,name,faceId))
        if affected_row != 0:
            return jsonify({
                "data":{
                    "faceId":faceId,
                    "name":name,
                    "img":local_path
                },
                "msg":"修改信息成功",
                "code":1
            })
        else:
            return jsonify({
                "msg":"修改信息失败",
                "code":-1
            })
    else:
        return jsonify({
            "face_encoding":"未识别到人脸" if len(face_encodings)==0 else "识别到多个人脸",
            "code":0
        })

@app.route('/download', methods=['POST'])
def download():
    url = request.json.get("url",None)
    if url == None:
        return jsonify({
            "code":0,
            "msg":"参数错误[url]"
        })
    local_path = os.path.join(".",url)
    if os.path.exists(local_path):
        return send_file(local_path,as_attachment=True)
    else:
        return jsonify({
            "code":0,
            "msg":"文件不存在"
        })

@app.route('/api', methods=['GET'])
def api():
    return render_template("api.html")

def jsonStr2arr(jsonArrStr):
    dataList =json.loads(jsonArrStr)
    if type(dataList) == list:
        return array(dataList,dtype=float64)
    return array([])

@app.before_request
def checkApiToken():
    if request.method =="POST":
        token = request.headers.get("X-TOKEN","")
        motken = None
        if True or str(request.url_rule) in AMIND_LOCALTION:
            motken = API_TOKEN["token"]
            request.mdata = API_TOKEN
        else:
            params = (0,1)
            datas = sql.select_infor("SELECT id,token FROM systoken LIMIT %s,%s",params)
            if len(datas) > 0:
                motken = datas[0]["token"]
                request.mdata= datas[0]

        if (token == None or token != motken):
            return jsonify({
                "code":0,
                "msg":"X-TOKEN 错误."
            })
        

@app.after_request
def errorRequest(rep):
    if rep.status_code <400:
        return rep
    return jsonify({
        "code":-1,
        "msg": str(rep.status_code)+"错误"
    })

@app.errorhandler(404) 
def page_not_found(error):
    return jsonify({
        "code":0,
        "msg":"未知请求"
    })

@app.errorhandler(500)
def errorhandler(error):
    return jsonify({
        "code":-1,
        "msg": str(error)
    })
    
if __name__ == "__main__":
    server = pywsgi.WSGIServer(('0.0.0.0',80),app)
    #app.run(host='0.0.0.0', port=80, debug=False)
    server.serve_forever()
